//
//  AIGirlApplePayCache.swift
//  AIGirl
//
//  Created by dongyx on 2024/5/20.
//

import UIKit
import KakaJSON
import MMKV
import StoreKit

extension Convertible {
    func alphaGo_identifier() -> String { "id" }
}

let AlphaGoCache = AIGirlApplePayCache.shared
class AIGirlApplePayCache: NSObject {
    
    static let shared = AIGirlApplePayCache()
    
    override init() {
        super.init()
        MMKV.initialize(rootDir: nil, logLevel: .none)
    }
    
    enum CacheKey {
        // 当前充值订单
        static let rechargeOrder        = "ALPHAGO_RECHARGEORDER"
        // 当前充值Id（消费）
        static let productId        = "ALPHAGO_PRODUCTID"
        // 当前充值Id（订阅）
        static let sub_productId        = "ALPHAGO_SUB_PRODUCTID"
    }
    
    // 未成功的交易订单
    var orderModel: AlphaGoTransactionModel? {
        get { objects(AlphaGoTransactionModel.self).first }
        set {
            if let newValue {
                // 有值的话就保存起来
                save(newValue)
            } else {
                remove(AlphaGoTransactionModel.self)
            }
        }
    }
    
    // 当前充值的订单，充值成功或者失败应该清空
    var currentOrderString: String? {
        get { MMKV.default()?.string(forKey: CacheKey.rechargeOrder) }
        set {
            if let newValue {
                // 有值的话就保存起来
                MMKV.default()?.set(newValue, forKey: CacheKey.rechargeOrder)
            } else {
                MMKV.default()?.removeValue(forKey: CacheKey.rechargeOrder)
            }
        }
    }
    
    var productIdentifier: String? {
        get { MMKV.default()?.string(forKey: CacheKey.productId) }
        set {
            if let newValue {
                // 有值的话就保存起来
                MMKV.default()?.set(newValue, forKey: CacheKey.productId)
            } else {
                MMKV.default()?.removeValue(forKey: CacheKey.productId)
            }
        }
    }
    
    /// 订阅
    var sub_productIdentifier: String? {
        get { MMKV.default()?.string(forKey: CacheKey.sub_productId) }
        set {
            if let newValue {
                // 有值的话就保存起来
                MMKV.default()?.set(newValue, forKey: CacheKey.sub_productId)
            } else {
                MMKV.default()?.removeValue(forKey: CacheKey.sub_productId)
            }
        }
    }
    
    /// 当前如果有未充值成功订单，启动之后，记录当前订单，避免用户点击取消
    var currentTranscation: SKPaymentTransaction?
    
}

extension AIGirlApplePayCache {
    
    enum AlphaGoCacheAppendKeyType {
        case normal
        
        var keyStr: String {
            switch self {
            default:
                return ""
            }
        }
    }
    
    //TODO: - 保存或者更新数据
    func save<T: Convertible>(_ models: [T]?, appendKey type: AlphaGoCacheAppendKeyType = .normal) {
        models?.forEach({ save($0, appendKey: type) })
    }
    func save<T: Convertible>(_ model: T?, appendKey type: AlphaGoCacheAppendKeyType = .normal) {
        guard let model else { return }
        //
        let classKey = classKey(model) + type.keyStr
        let modelInfo = model.kj.JSONObject()
        let model_identifierKey = model.alphaGo_identifier()
        if var datas = MMKV.default()?.object(of: NSArray.classForCoder(), forKey: classKey) as? [[String: Any]] {
            if let index = datas.firstIndex(where: { info in
                return (info[model_identifierKey] as? String) == (modelInfo[model_identifierKey] as? String)
            }) {
                datas.remove(at: index)
                datas.insert(modelInfo, at: index)
            } else {
                datas.append(modelInfo)
            }
            MMKV.default()?.set(datas as (NSCoding & NSObjectProtocol), forKey: classKey)
        } else {
            MMKV.default()?.set( [modelInfo] as (NSCoding & NSObjectProtocol), forKey: classKey)
        }
    }
    
    //TODO: - 获取数据
    func objects<T: Convertible>(_ model: T.Type, appendKey type: AlphaGoCacheAppendKeyType = .normal) -> [T] {
        let classKey = classKey(model) + type.keyStr
        if let datas = MMKV.default()?.object(of: NSArray.classForCoder(), forKey: classKey) as? [[String: Any]] {
            return datas.kj.modelArray(model.self)
        }
        return []
    }
    
    //TODO: - 删除一个数据
    func delete<T: Convertible>(_ model: T, appendKey type: AlphaGoCacheAppendKeyType = .normal) {
        let classKey = classKey(model) + type.keyStr
        
        let modelInfo = model.kj.JSONObject()
        let model_identifierKey = model.alphaGo_identifier()
        if let datas = MMKV.default()?.object(of: NSArray.classForCoder(), forKey: classKey) as? [[String: Any]] {
            let infos = datas.filter { info in
                return (info[model_identifierKey] as? String) == (modelInfo[model_identifierKey] as? String)
            }
            MMKV.default()?.set(infos as (NSCoding & NSObjectProtocol), forKey: classKey)
        }
    }
    
    //TODO: - 删除一组数据
    func remove<T: Convertible>(_ model: T, appendKey type: AlphaGoCacheAppendKeyType = .normal) {
        let classKey = classKey(model) + type.keyStr
        MMKV.default()?.removeValue(forKey: classKey)
    }
    func remove<T: Convertible>(_ model: T.Type, appendKey type: AlphaGoCacheAppendKeyType = .normal) {
        let classKey = classKey(model) + type.keyStr
        MMKV.default()?.removeValue(forKey: classKey)
    }
    
    //TODO: - Clean
    func clean() {
        MMKV.default()?.clearAll()
    }
    
}

private extension AIGirlApplePayCache {
    
    //TODO: - Target name
    func targetName() -> String { ((Bundle.main.infoDictionary?["CFBundleExecutable"] as? String) ?? "") }
    
    private func classKey<T>(_ type: T.Type) -> String {
        let classKey = String(describing: type)
        if classKey.contains("("), let structName = classKey.components(separatedBy: "(").first {
            return structName.replacingOccurrences(of: "\(targetName()).", with: "")
        }
        return classKey.replacingOccurrences(of: "\(targetName()).", with: "")
    }
    
    private func classKey<T>(_ type: T) -> String {
        let classKey = String(describing: type)
        if classKey.contains("("), let structName = classKey.components(separatedBy: "(").first {
            return structName.replacingOccurrences(of: "\(targetName()).", with: "")
        }
        return classKey.replacingOccurrences(of: "\(targetName()).", with: "")
    }
    
}

